package com.ruoyi.file.service.impl;

import com.ruoyi.blog.core.domain.AjaxResult;
import com.ruoyi.file.constant.CommonConstant;
import com.ruoyi.file.domain.po.FileBo;
import com.ruoyi.file.domain.po.FileInfo;
import com.ruoyi.file.domain.po.FileProCol;
import com.ruoyi.file.mapper.FileMapper;
import com.ruoyi.file.mapper.FileProColMapper;
import com.ruoyi.file.service.FileService;
import com.ruoyi.file.storage.platform.MinioStorage;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

import static com.ruoyi.blog.utils.SecurityUtils.getUserId;

/**
 * @Author: 依梦
 * @Date: 2024/10/6
 * @Description: FileServiceImpl
 */
@Slf4j
@Service
public class FileServiceImpl implements FileService {

    @Resource
    private FileMapper fileMapper;
    @Resource
    private MinioStorage localStorage;
//    private LocalStorage localStorage;

    @Resource
    private FileProColMapper fileProColMapper;

    // 事务
    @Resource
    private TransactionTemplate transactionTemplate;


    @Override
    public List<FileInfo> getList(FileInfo info) {
        String dirIds = info.getDirIds();
        if (StringUtils.isNotEmpty(dirIds)) {
            dirIds = dirIds.substring(dirIds.lastIndexOf(CommonConstant.DIR_SPLIT) + 1);
        }
        info.setParentId(StringUtils.isEmpty(dirIds) ? CommonConstant.ROOT_PARENT_ID : Long.parseLong(dirIds));
        return fileMapper.getList(info);
    }

    @Override
    public AjaxResult upload(MultipartFile[] files, String dirIds) {
        if (files == null || files.length == 0) {
            throw new RuntimeException("文件不能为空");
        }
        for (MultipartFile file : files) {
            // 1. 先将文件上传到本地
            FileInfo fileInfo = uploadFile(file);
            // 文件目录id
            String dirId = dirIds.substring(dirIds.lastIndexOf(CommonConstant.DIR_SPLIT) + 1);
            if (CommonConstant.DIR_SPLIT.equals(dirId)
                    || StringUtils.isEmpty(dirId)) {
                fileInfo.setParentId(CommonConstant.ROOT_PARENT_ID);
            } else {
                // 通过文件目录id去查询父级目录
                FileInfo f = fileMapper.getById(Long.parseLong(dirId));
                fileInfo.setParentId(f.getId());
            }
            int flag = 0;
            fileInfo.setName(recursionFindName(fileInfo.getName(), fileInfo.getName(), fileInfo.getParentId(), flag));
            fileInfo.setUserId(getUserId());
            // 保存文件
            if (!fileMapper.save(fileInfo)) {
                return AjaxResult.error("文件：" + file.getOriginalFilename() + "上传失败");
            }
        }
        return AjaxResult.success("上传成功");
    }

    @Override
    public boolean addFolder(FileInfo info) {
        String dirId = info.getDirIds().substring(info.getDirIds().lastIndexOf(CommonConstant.DIR_SPLIT) + 1);
        if (CommonConstant.DIR_SPLIT.equals(dirId) || StringUtils.isEmpty(dirId)) {
            info.setParentId(CommonConstant.ROOT_PARENT_ID);
        } else {
            FileInfo fileInfo = fileMapper.getById(Long.parseLong(dirId));
            info.setParentId(fileInfo.getId());
        }
        info.setType(CommonConstant.DEFAULT_DIR_TYPE);
        info.setIsDir(Boolean.TRUE);
        info.setIsImg(Boolean.FALSE);
        info.setUserId(getUserId());
        //判断文件夹名称在当前目录中是否存在
        FileInfo infoCount = new FileInfo();
        infoCount.setName(info.getName());
        infoCount.setIsDir(Boolean.TRUE);
        infoCount.setParentId(info.getParentId());
        infoCount.setUserId(info.getUserId());
        Integer count = fileMapper.count(infoCount);
        if (count > 0) {
            throw new RuntimeException("当前目录名称已存在，请修改名称！");
        }
        return fileMapper.save(info);
    }

    @Override
    public List<FileProCol> uploadProject(Long projectId, Long columnsId, Long issueId, MultipartFile[] files) {
        if (files == null || files.length == 0) {
            throw new RuntimeException("文件不能为空");
        }
        List<FileProCol> results = new ArrayList<>();
        // 手动
        Boolean uploadStatus = transactionTemplate.execute((state) -> {
            try {
                for (MultipartFile file : files) {
                    // 将文件进行上传
                    FileProCol fileInfo = uploadProjectFile(getBigPath(projectId, issueId, columnsId), file);
                    fileInfo.setProjectId(projectId);
                    fileInfo.setColumnsId(columnsId);
                    fileInfo.setIssueId(issueId);
                    fileInfo.setName(recursionFindName(fileInfo.getName(), fileInfo.getName(), null, 0));
                    fileInfo.setUserId(getUserId());
                    // 保存文件
                    if (fileProColMapper.insert(fileInfo) <= 0) {
                        throw new RuntimeException("文件：" + file.getOriginalFilename() + "上传失败");
                    }
                    results.add(fileInfo);
                }
            } catch (Exception e) {
                log.error("文件上传失败...");
                // 回滚
                e.printStackTrace();
                state.setRollbackOnly();
                return false;
            }
            return true;
        });

        if (Boolean.FALSE.equals(uploadStatus)) {
            throw new RuntimeException("文件上传失败");
        }
        return results;
    }


    // TODO
    private String getBigPath(Long projectId, Long issueId, Long columnsId) {
        String lastPath = "";
        if (projectId == 1) {
            return "blog";
        } else if (projectId == 3) {
            // 博客文章相关的
            // 0 表示文章封面
            // 1 表示文章中其他内容存放
            lastPath += "article" + CommonConstant.DIR_SPLIT;
            if (issueId == 0) {
                // 封面 cover
                lastPath += "cover";
            } else if (issueId == 1) {
                // 文章中的
                lastPath += "content";
            }
        }
        // 头像边框
        else if(projectId == 4){
            lastPath += "avatar_border";
        }
        // 加上表 id
        return lastPath + CommonConstant.DIR_SPLIT + columnsId + CommonConstant.DIR_SPLIT;
    }

    @Override
    public List<FileProCol> getFileInfo(Long projectId, Long issueId, Long columnsId) {
        // 根据这三个条件查询对应的文件出来
        return fileProColMapper.getList(projectId, issueId, columnsId);
    }

    @Override
    public FileProCol getOneFileInfo(Long projectId, Long issueId, Long columnsId) {
        // 根据这三个条件查询对应的文件出来
        List<FileProCol> list = fileProColMapper.getList(projectId, issueId, columnsId);
        if (list.size() == 0) {
            return null;
        }
        return list.get(0);
    }

    @Override
    public Boolean deleteFileProById(Long id) {
        // 先查询出来
        FileProCol fileProCol = fileProColMapper.selectById(id);
        // 根据存储的路径将文件删除
        return transactionTemplate.execute(transactionStatus -> {
            try {
                // 去掉 /uploads 前缀
                String url = fileProCol.getUrl().substring(8);
                localStorage.deleteUpload(url);
                fileProColMapper.deleteById(id);
            } catch (Exception e) {
                transactionStatus.setRollbackOnly();
                return false;
            }
            return true;
        });
    }


    private FileInfo uploadFile(MultipartFile file) {
        FileBo bo = localStorage.upload(file);
        FileInfo fileInfo = new FileInfo();
        BeanUtils.copyProperties(bo, fileInfo);
        return fileInfo;
    }


    private FileProCol uploadProjectFile(String path, MultipartFile file) {
        FileBo bo = localStorage.uploadProject(path, file);
        FileProCol fileInfo = new FileProCol();
        BeanUtils.copyProperties(bo, fileInfo);
        return fileInfo;
    }

    private String recursionFindName(String sname, String rname, Long parentId, int flag) {
        boolean exists = true;
        while (exists) {
            FileInfo fileInfo = new FileInfo();
            fileInfo.setName(rname);
            fileInfo.setIsDir(Boolean.FALSE);
            fileInfo.setParentId(parentId);
            Integer count = fileMapper.count(fileInfo);
            if (count > 0) {
                flag++;
                rname = sname + "(" + flag + ")";
            } else {
                exists = false;
            }
        }
        return flag > 0 ? sname + "(" + flag + ")" : sname;
    }

}
